package cz.muni.fi.pv112.cranesimulator.utils.loaders;

import cz.muni.fi.pv112.cranesimulator.models.OBJModel;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.List;
import static java.lang.Float.parseFloat;
import static java.lang.Integer.parseInt;

/**
 *
 * Author: Matúš Kotry
 * Modification: Michal Ďuriš
 */
public class ObjLoader {

    private OBJModel model;

    private BufferedReader inReader;

    public ObjLoader() {
    }

    public void load(OBJModel model) {
        this.model = model;
        load();
    }

    public OBJModel load(String path) {
        model = new OBJModel();
        model.setPath(path);

        load();

        return model;
    }

    private void load() {
        String line;

        List<float[]> vertices = model.getVertices();
        List<int[]> vertexIndices = model.getVertexIndices();

        List<float[]> textures = model.getTextures();
        List<int[]> textureIndices = model.getTextureIndices();

        List<float[]> normals = model.getNormals();
        List<int[]> normalIndices = model.getNormalIndices();

        try {
            inReader = new BufferedReader(new InputStreamReader(
                    this.getClass().getResource(model.getPath()).openStream()));

            while ((line = inReader.readLine()) != null) {

                if (line.startsWith("v ")) {

                    String[] vertStr = line.split("\\s+");
                    float[] vertex = new float[3];

                    vertex[0] = parseFloat(vertStr[1]);
                    vertex[1] = parseFloat(vertStr[2]);
                    vertex[2] = parseFloat(vertStr[3]);
                    vertices.add(vertex);

                } else if (line.startsWith("vn ")) {

                    String[] normStr = line.split("\\s+");
                    float[] normal = new float[3];

                    normal[0] = parseFloat(normStr[1]);
                    normal[1] = parseFloat(normStr[2]);
                    normal[2] = parseFloat(normStr[3]);
                    normals.add(normal);

                } else if (line.startsWith("vt ")) {

                    String[] textureCoordString = line.split("\\s+");
                    float[] textureCoord = new float[2];

                    textureCoord[0] = parseFloat(textureCoordString[1]);
                    textureCoord[1] = parseFloat(textureCoordString[2]);

                    textures.add(textureCoord);

                } else if (line.startsWith("f ")) {

                    String[] faceStr = line.split("\\s+");

                    if (faceStr[1].split("//").length == 2) {
                        vertexIndices
                                .add(getProcessedFaceItem(faceStr, 0, "//"));

                        normalIndices
                                .add(getProcessedFaceItem(faceStr, 1, "//"));
                    } else if (faceStr[1].split("/").length >= 2) {
                        vertexIndices.add(getProcessedFaceItem(faceStr, 0, "/"));

                        textureIndices
                                .add(getProcessedFaceItem(faceStr, 1, "/"));

                        if (faceStr[1].split("/").length >= 3) {
                            normalIndices.add(getProcessedFaceItem(faceStr, 2,
                                    "/"));
                        }
                    } else if (faceStr[1].split("/").length == 1) {
                        vertexIndices.add(getProcessedFaceItem(faceStr));
                    }
                }
            }
        } catch (IOException ex) {
            System.out.println("Unable to load " + model.getPath() + " file: "
                    + ex.getMessage());
        } finally {
            if (inReader != null) {
                try {
                    inReader.close();
                } catch (IOException ex) {
                }
            }
        }
    }

    private int[] getProcessedFaceItem(String[] faceLine) {
        return getProcessedFaceItem(faceLine, -1, null);
    }

    private int[] getProcessedFaceItem(String[] faceLine, int faceItemIndex,
                                       String faceItemDelimeter) {
        int[] faceItemField = new int[faceLine.length - 1];

        for (int i = 0; i < faceItemField.length; i++) {
            if (faceItemDelimeter == null) {
                faceItemField[i] = parseInt(faceLine[i + 1]) - 1;
            } else {
                faceItemField[i] = parseInt(faceLine[i + 1].split(
                        faceItemDelimeter)[faceItemIndex]) - 1;
            }
        }

        return faceItemField;
    }

}
